package com.cskaoyan.javase.oop3._2inner._5anonymous._0introduction;

/**
 * 本节内部类对象，本质上还是属于定义在别的类内部的一个类。
 * 但区别是：
 * 成员内部类、静态内部类和局部内部类都属于定义了一个类，后续使用还需要基于内部类创建对象。
 * 而本节中的匿名内部类和Lambda表达式都是直接通过语法创建了对象。
 * 其实想一想，我们定义内部类，最终还是为了获取对象使用，所以实际开发中匿名内部和Lambda表达式会更常见和常用。
 * 最后，在学习匿名内部类和Lambda表达式之前，我们还是要清楚——它们都是特殊的局部内部类。所以一旦访问方法的局部变量，该局部变量需要是一个常量。
 *
 * 什么是匿名内部类?
 * 我们已经使用过匿名对象了，匿名对象的含义是这个对象是没有名字，没有引用指向它。
 * 那么匿名内部类，指的就是这个内部类没有名字。当然成员内部类和静态内部类没法没有名字
 * 所以 匿名内部类指的是"没有名字的局部内部类"。是一种特殊的局部内部类。
 *
 * 匿名内部类是对继承/实现某个类/接口的局部内部类的简化
 * 它的语法是:
 * // 局部位置
 * new 类名或者接口名(){
 *   // 某类名或接口名的子类的类体
 * };
 * // 局部位置
 *
 * 解释:
 *      1.new关键字表示创建对象
 *      2.语法中"类名或者接口名"的位置,可以写普通类,也可以写抽象类
 *      3.匿名内部类的语法,并不是在局部位置定义类,而是在局部位置直接创建对象
 *          接口,抽象类显然是没有对象的
 *          所以这里实际上创建的是语法当中"类名或者接口名"的子类对象
 *          匿名内部类的语法中,隐含了继承或者实现,创建的对象都是子类对象
 *          并且这个子类的名字是不确定的,所以称之为"匿名内部类"
 *          当然,该语法实际上是创建了对象,更准确的称呼是"匿名内部类对象"
 *      4.匿名内部类语法中的大括号是什么意思?(重要)
 *          大括号是匿名子类的类体
 *          既然是类体,那么就可以在匿名子类类体中定义匿名子类自身独有成员
 *          也可以重写父类中的方法
 *      A() {
 *          // 匿名子类的类体
 *         };
 *         是匿名子类的类体
 *         new关键字表示创建对象
 *
 *
 * 匿名内部类是创建了一个子类对象,那么这个子类对象如何去使用呢?
 *      1.把匿名内部类对象直接当成一个匿名对象去使用(直接使用)
 *      2.用引用接收,然后再使用(只能用父类引用接收,子类是匿名的,不知道子类是谁)
 *
 *      比较一下上述两种使用方式:
 *      直接使用
 *          优点: 更简单,更方便,更快,而且可以访问子类自身独有成员
 *
 *          缺点: 一次性,用完再也用不了这个匿名子类对象了.
 *
 *      引用接收再使用
 *          优点: 不是一次性的,可以多次使用这个匿名子类对象
 *
 *          缺点: 稍微麻烦一点(不多)
 *              最重要的是父类引用限制了匿名子类对象的访问范围,父类引用无法访问子类独有成员
 *              并且是真的无法访问,不能强转(因为匿名子类,子类不知道是谁,没有办法强转)
 *
 * @since 11:11
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        new EnclosedClazz().method();
    }
}

class EnclosedClazz {
    public void method() {
        // 匿名内部类对象,创建类A的子类对象,当然这个子类是什么不知道,是匿名的
        new A() {
            @Override
            void test() {
                System.out.println("我是匿名内部类的类体中重写父类的方法!");
            }
            void test2(){}
        }.test2();

        // 用匿名内部类创建抽象类的子类对象,这个子类是匿名的,但是这个子类对象的父类是BaseA
        BaseA ba = new BaseA() {
            @Override
            public void test() {
                System.out.println("我是抽象类的匿名子类对象!");
            }
            void test2(){}
        };
        ba.test();
        // ba.test2();
    }
}

abstract class BaseA {
    public abstract void test();
}

class A {
    void test() {
        System.out.println("A");
    }
}
